﻿using System;
#pragma warning disable SYSLIB0023 // 类型或成员已过时

namespace Sunny.UI
{
    /*
       Func<int, long> function = x => x * (x - 1) * (x - 3);
       string key2 = CreateKey(function, 3456);
       Console.WriteLine(ValidateKey(key2, function, 3456));
       Console.ReadKey();
    */

    public static class ULicensing
    {
        public static string CreateKey(Func<int, long> f, int mod)
        {
            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
            byte[] rndBytes = new byte[4];
            rng.GetBytes(rndBytes);
            int rand = modulo(BitConverter.ToInt32(rndBytes, 0), mod);
            int key = modulo(f(rand), mod);

            rng.GetBytes(rndBytes);
            int rand2 = modulo(BitConverter.ToInt32(rndBytes, 0), mod);
            int key2 = modulo(f(rand2), mod);

            rng.GetBytes(rndBytes);
            int rand3 = modulo(BitConverter.ToInt32(rndBytes, 0), mod);
            int key3 = modulo(f(rand3), mod);

            decimal outputData = 1; //this could've been 0 too, however, in that case, we would need
                                    //to take this into consideration when the key is deciphered (the length)

            outputData *= (decimal)Math.Pow(10, mod.ToString().Length);
            outputData += rand;
            outputData *= (decimal)Math.Pow(10, mod.ToString().Length); //maybe need a one somewhere to fill up the space
            outputData += key;
            outputData *= (decimal)Math.Pow(10, mod.ToString().Length);

            outputData += rand2;
            outputData *= (decimal)Math.Pow(10, mod.ToString().Length);
            outputData += key2;
            outputData *= (decimal)Math.Pow(10, mod.ToString().Length);

            outputData += rand3;
            outputData *= (decimal)Math.Pow(10, mod.ToString().Length);
            outputData += key3;

            string output = MathEx.Base10ToBase26(outputData.ToString());

            return output;
        }

        public static bool ValidateKey(string key, Func<int, long> f, int mod)
        {
            string base10 = MathEx.Base26ToBase10(key);
            int modLength = mod.ToString().Length;

            for (int i = 0; i < 3; i++)
            {
                if (modulo(f(Convert.ToInt32(base10.Substring(1, modLength))), mod) == Convert.ToInt32(base10.Substring(modLength + 1, modLength)))
                {
                    base10 = base10.Substring(2 * modLength);
                }
                else
                {
                    return false;
                }
            }

            return true;
        }

        private static decimal maxModValue()
        {
            //this is the maximum length of mod variable considering we
            //have 3 points (1 point = 2 values).
            return (decimal.MaxValue.ToString().Length - 1) / 6;
        }

        private static int modulo(long _num, long _base)
        {
            return (int)(_num - _base * Convert.ToInt64(Math.Floor((decimal)_num / (decimal)_base)));
        }

    }
}
